package com.dianpingmedia.wifitz.read.serial;

import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;

import com.dianpingmedia.wifitz.read.listener.IReader;
import com.dianpingmedia.wifitz.read.listener.OnOutputListener;
import com.dianpingmedia.wifitz.utlis.RssiMeterUtil;
import com.dianpingmedia.wifitz.utlis.SPUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Locale;

import android_serialport_api.SerialPort;

/**
 * @author zsc
 * @create 2018/3/19 0019
 * @Describe
 */
public class SerialPortManager implements IReader {
    public OnOutputListener mOnOutputListener = null;
    public InputStream mIs = null;
    public OutputStream mOs = null;
    private SerialPort mSerialPort = null;
    private final static int BAUDRATE = 115200;
    private boolean mSerialPortStatus = false;
    private final static String TAG = SerialPortManager.class.getSimpleName();
    private boolean mThreadStatus = false;
    private ReadThread mReadThread;
    private byte[] tempByte;
    public final int LF = 10;//换行符-asci
    private Handler mHandler;
    private String usbtty = SPUtils.getUsbtty();

    private SerialPortManager() {

    }

    public void addOnOutputListener(OnOutputListener onOutputListener) {
        this.mOnOutputListener = onOutputListener;
    }


    public void setHandler(Handler handler) {
        mHandler = handler;
    }

    private static class Holder {
        private static final SerialPortManager mInstance = new SerialPortManager();

        private static SerialPortManager newInstance() {
            return mInstance;
        }
    }

    public static SerialPortManager getInstance() {
        return Holder.newInstance();
    }

    public void start(int tyeTimes) {
        if (isSerialPortStatus()) {
            return;
        }
        usbtty = SPUtils.getUsbtty();
        try {
            stop();
            mSerialPort = new SerialPort(new File(usbtty), BAUDRATE, 0);
            mSerialPortStatus = true;
            mThreadStatus = true;
            mIs = mSerialPort.getInputStream();
            mOs = mSerialPort.getOutputStream();
            mReadThread = new ReadThread();
            mReadThread.start();
            sendLog(usbtty + "--串口打开成功,开始读取数据\n");
        } catch (IOException e) {
            if (--tyeTimes > 0) {
                start(tyeTimes);
            } else {
                sendLog(usbtty + "--串口打开失败,请右滑重新设置usbtty串口地址\n");
            }
        }
    }

    private boolean isSerialPortStatus() {
        return mSerialPortStatus;
    }

    private boolean usbttyIsChanged() {
        return !usbtty.equals(SPUtils.getUsbtty());
    }

    /**
     * 关闭串口
     */
    public void stop() {
        if (mSerialPortStatus) {
            try {
                mThreadStatus = false;
                mSerialPortStatus = false;
                if (mIs != null) {
                    mIs.close();
                }
                if (mOs != null) {
                    mOs.close();
                }
                if (mSerialPort != null) {
                    mSerialPort.close();
                    mSerialPort = null;
                }
            } catch (IOException e) {
                sendLog("串口关闭出错\n");
            }
        }
    }

    @Override
    public void reboot() {
        if (usbttyIsChanged()) {
            stop();
            sendLog("-----usbtty发送改变重启探测服务------\n");
            start(2);
        }
    }

    /**
     * 单开一线程，来读数据
     */
    private class ReadThread extends Thread {
        @Override
        public void run() {
            super.run();
            //判断进程是否在运行，更安全的结束进程
            while (mThreadStatus) {
                int size; //读取数据的大小
                try {
                    byte[] buffer = new byte[mIs.available()];
                    size = mIs.read(buffer);
                    if (size > 0) {
                        String message = dealUsbMessage(buffer);
                        if (!TextUtils.isEmpty(message)) {
                            mOnOutputListener.onSuccess(message);
                        }
                    }
                } catch (IOException e) {
                    sendLog("---数据读取异常\n");
                    e.printStackTrace();
                }
            }

        }
    }

    /**
     * 发送串口指令（字符串）
     *
     * @param data String数据指令
     */
    private void sendSerialPort(String data) {
        if (mSerialPortStatus) {
            try {
                byte[] sendData = data.getBytes();
                String data_ = new String(sendData);
                if (sendData.length > 0) {
                    mOs.write(sendData);
                    mOs.write('\n');
                    //outputStream.write('\r'+'\n');
                    mOs.flush();
                }
            } catch (IOException e) {
            }
        } else {
        }
    }


    /**
     * 根据换行符字节来 处理数据
     *
     * @param data
     * @return 返回完整的数据(以换行结尾)
     */
    private String dealUsbMessage(byte[] data) {

        if (data == null)
            return null;
        //        MyLog.w(TAG, byteToString(data));
        long start = System.currentTimeMillis();
        //处理返回字节
        //加上上次剩余字节，一同处理
        //截取至数组最后一个换行符字节解析，其余的添加至tempByte
        int lastLF = -1;
        final int lenData = data == null ? 0 : data.length;
        final int lenTem = tempByte == null ? 0 : tempByte.length;
        //寻找data中最后一个换行符

        int i = lenData - 1;
        while (i >= 0) {
            if (data[i] == LF) {
                lastLF = i;
                break;
            }
            --i;
        }
        //有效數據
        String msg = null;

        //缓存长度为0，且byte[]data已换行符结尾，则数据可以解析
        if (lenTem == 0 && lastLF == lenData) {
            msg = byteToString(data);
            //            MyLog.v(TAG, "temNull ----msg = " + msg);
        } else if (lastLF >= 0) {//含换行符且换行符不在结尾
            //生成新的字節數組
            byte[] strByte = new byte[lenTem + lastLF + 1];

            if (lenTem > 0)
                System.arraycopy(tempByte, 0, strByte, 0, lenTem);
            System.arraycopy(data, 0, strByte, lenTem, lastLF + 1);
            msg = byteToString(strByte);
            //            MyLog.v(TAG, "tem l ++++ msg = " + msg);
        }
        //生成新的tempByte;
        if (lastLF >= 0) {
            tempByte = new byte[lenData - lastLF - 1];
            tempByte = Arrays.copyOfRange(data, lastLF, lenData);
        } else {

            byte[] newByte = new byte[lenData + lenTem];

            if (lenTem > 0)
                System.arraycopy(tempByte, 0, newByte, 0, lenTem);
            System.arraycopy(data, 0, newByte, lenTem, lenData);
            tempByte = newByte;
        }
        //        MyLog.v(TAG, "tem  >>>> " + byteToString(tempByte));
        return deleteData(msg);
    }

    private String byteToString(byte[] data) {
        try {
            return new String(data, "utf-8");
        } catch (UnsupportedEncodingException e) {
            return new String(data);
        } catch (NullPointerException e) {
            return "";
        }
    }


    private String deleteData(String msg) {
        if (TextUtils.isEmpty(msg))
            return msg;
        String[] lineStrArr = msg.split("\n");
        if (lineStrArr.length > 0) {
            int startIndex = 1;
            String lineStr = lineStrArr[0];
            if (TextUtils.isEmpty(lineStr)) {
                try {
                    lineStr = lineStrArr[1];
                } catch (Exception e) {
                    return msg;
                }
                startIndex = 2;
            }
            String[] dataArr = lineStr.split("\\|");
            if (true) {
                //            if (dataArr.length > 0 && (dataArr.length < 5 || dataArr[0].length() != 17)) {
                StringBuffer sb = new StringBuffer();
                //                Log.i("数据", "丢弃" + lineStrArr[startIndex - 1]);
                for (int i = startIndex; i < lineStrArr.length; i++) {//丢弃第一行
                    sb.append(lineStrArr[i] + "\n");
                }
                return sb.toString();
            }
        }
        return msg;
    }

    private void writeToWifiTz(int meter) {
        String data = "AT+RSSI=" + RssiMeterUtil.meterToRssi(meter) + "\\r\\n";
    }

    private void sendLog(String log) {
        if (!TextUtils.isEmpty(log)) {
            Log.i(TAG, log);
            if (mHandler != null) {
                Message obtain = Message.obtain();
                obtain.what = 0;
                obtain.obj = log;
                mHandler.sendMessage(obtain);
            }
        }
    }

}
